#pragma once

#include <iostream>
#include <queue>

#include <pthread.h>

#include "Task.hpp"
#include "Log.hpp"

#define NUM 5

class ThreadPool
{
  public:
    static ThreadPool* getinstance()
    {
        static pthread_mutex_t getinstance_lock = PTHREAD_MUTEX_INITIALIZER;
        if(single_instance == nullptr)
        {
            pthread_mutex_lock(&getinstance_lock);
            if(single_instance == nullptr)
            {
                single_instance = new ThreadPool();
                single_instance->InitThreadPool();
            }
            pthread_mutex_unlock(&getinstance_lock);
        }
        return single_instance;
    }
    bool IsStop()
    {
        return _stop;
    }
    bool TaskQueueIsEmpty()
    {
        return _task_queue.size() == 0 ? true : false;
    }
    void Lock() //加锁
    {
        pthread_mutex_lock(&_lock);
    }
    void Unlock() //解锁
    {
        pthread_mutex_unlock(&_lock);
    }
    void ThreadWait() //线程等待
    {
        pthread_cond_wait(&_cond, &_lock);
    }
    void ThreadWakeup() //线程唤醒
    {
        pthread_cond_signal(&_cond);
    }
    static void *ThreadRoutine(void *args)  //线程例程
    {
        ThreadPool *thread_pool_pointer = (ThreadPool*)args;
        while(true)
        {
            Task task;
            thread_pool_pointer->Lock();
            while(thread_pool_pointer->TaskQueueIsEmpty())  //while是防止伪唤醒
            {
                thread_pool_pointer->ThreadWait();
            }
            thread_pool_pointer->PopTask(task); //从任务队列中获取新任务
            thread_pool_pointer->Unlock();
            task.ProcessOn();
        }
    }
    bool InitThreadPool()
    {
        for(int i = 0; i < _num; i++)
        {
            pthread_t tid;
            if(pthread_create(&tid, nullptr, ThreadRoutine, this) != 0)
            {
                LOG(FATAL, "create pthread pool error");
                return false;
            }
        } 
        LOG(INFO, "create pthread pool success");
        return true;
    }
    void PushTask(const Task& task)
    {
        Lock();
        _task_queue.push(task);
        Unlock();
        ThreadWakeup();
    }
    void PopTask(Task& task)
    {
        task = _task_queue.front();
        _task_queue.pop();
    }
    ~ThreadPool()
    {
      pthread_mutex_destroy(&_lock);
      pthread_cond_destroy(&_cond);
    }
  private:
    ThreadPool(int num = NUM)
      : _num(num)
      , _stop(false)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    ThreadPool(const ThreadPool &)
    {}
  private:
    int _num;  //线程数量
    bool _stop;    //是否停止
    std::queue<Task> _task_queue;  //任务队列
    pthread_mutex_t _lock; //互斥锁
    pthread_cond_t _cond;  //条件变量
    static ThreadPool *single_instance; //线程池单例指针
};

ThreadPool* ThreadPool::single_instance = nullptr;